from PyQt5 import QtWidgets, QtCore
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.Qt import QMessageBox, QFont, QPalette, QBrush
import os

from PyQt5.QtWidgets import QMessageBox, QWidget, QGridLayout, QPushButton, QMenu
from loguru import logger

from ui.base._config import UI_RES_PATH
from ui.base.ui_utils import explorer
from workers.image_producer.factory import resize_factory


class ImgViewer(QtWidgets.QLabel):
    def __init__(self, parent=None, app=None):
        super().__init__(parent)
        self.app = app
        self.win = ShowImgPage(main_window=parent)
        self.img_path = None
        self._img_struct = None

    @property
    def img_struct(self):
        return self._img_struct

    @img_struct.setter
    def img_struct(self, value):
        self._img_struct = value
        self.win.content.img_struct = value

    def mouseDoubleClickEvent(self, e):
        if self.img_path is not None and os.path.exists(self.img_path):
            self.show_img(QPixmap(str(self.img_path)))
        elif self.pixmap():
            self.show_img(self.pixmap())
        logger.debug(f"clicked img_struct: {self.img_struct.to_dict()}")

    def get_path_list(self):
        path_list = []
        for d in self.app.img_info_cached:
            path_list.append(str(d['img_path']))
        return path_list

    def show_img(self, img):
        self.win.path_list = self.get_path_list()
        self.win.current_path = self.img_path
        window_title = self.img_path.split('\\')[-1]
        self.win.setWindowTitle(window_title)
        self.win.content(img)
        self.win.show()


class ShowImgPage(QWidget):
    def __init__(self, main_window, img_struct=None):
        super().__init__()
        self.main_window = main_window
        self.w = 1600
        self.h = 1300
        self.path_list = []  # 初始化 path_list
        self.current_path = None  # 初始化 current_path
        self.setFixedSize(self.w, self.h)
        self.window_icon = QIcon(str(UI_RES_PATH / 'logo.png'))
        self.setWindowIcon(self.window_icon)
        grid = QGridLayout()
        self.setLayout(grid)

        # 图片内容区域
        self.content = ImgContent((self.w - 150, self.h - 20), img_struct)

        # 上一页按钮
        self.back_btn = QPushButton(self)
        self.back_btn.setText('<<')
        self.set_button_style(self.back_btn)
        self.back_btn.clicked.connect(self.back)

        # 下一页按钮
        self.next_btn = QPushButton(self)
        self.next_btn.setText('>>')
        self.set_button_style(self.next_btn)
        self.next_btn.clicked.connect(self.next)

        # 布局添加控件
        grid.addWidget(self.back_btn, 0, 1)
        grid.addWidget(self.content, 0, 2)
        grid.addWidget(self.next_btn, 0, 3)

    def set_button_style(self, button):
        """设置按钮样式"""
        button.setStyleSheet('background-color:rgb(192, 192, 192)')
        button.setFixedSize(50, self.h - 20)

    def update_image(self, new_path):
        """更新图片"""
        try:
            if not os.path.exists(new_path):
                raise FileNotFoundError(f"图片路径不存在: {new_path}")
            if not self.is_valid_image(new_path):
                raise ValueError(f"无效的图片文件: {new_path}")

            # 更新图片内容
            self.content(QPixmap(new_path))
            self.setWindowTitle(os.path.basename(new_path))  # 跨平台兼容
        except Exception as e:
            logger.error(f"加载图片失败: {new_path}, 错误信息: {e}")
            self.content.setText('加载图片失败，请检查路径是否正确！')

    @staticmethod
    def is_valid_image(path):
        """验证路径是否为合法图片文件"""
        valid_extensions = ['.png', '.jpg', '.jpeg', '.bmp', '.gif']
        return any(path.lower().endswith(ext) for ext in valid_extensions)

    def back(self):
        """上一页"""
        if not self.path_list or self.current_path is None:
            msg = '当前没有图片！'
            QMessageBox.information(self, '提示', msg, QMessageBox.Yes)
            return

        if self.current_path not in self.path_list:
            logger.warning(f"当前路径不在路径列表中: {self.current_path}")
            return

        i = self.path_list.index(self.current_path)
        if i > 0:
            self.current_path = self.path_list[i - 1]
            self.update_image(self.current_path)
        else:
            msg = '已至第一张图片！'
            QMessageBox.information(self, '提示', msg, QMessageBox.Yes)

    def next(self):
        """下一页"""
        if not self.path_list or self.current_path is None:
            msg = '当前没有图片！'
            QMessageBox.information(self, '提示', msg, QMessageBox.Yes)
            return

        if self.current_path not in self.path_list:
            logger.warning(f"当前路径不在路径列表中: {self.current_path}")
            return

        i = self.path_list.index(self.current_path)
        if i < len(self.path_list) - 1:
            self.current_path = self.path_list[i + 1]
            self.update_image(self.current_path)
        else:
            msg = '已至最后一张图片！'
            QMessageBox.information(self, '提示', msg, QMessageBox.Yes)


class ImgContent(QtWidgets.QLabel):
    def __init__(self, size, img_struct):
        super().__init__()
        self.size = size  # TODO 暂时先写死
        font = QFont()
        font.setBold(True)
        font.setPointSize(15)
        self.setFont(font)
        self.setAlignment(QtCore.Qt.AlignCenter)
        self.img_struct = img_struct
        self._img_path = None
        self._ori_img_path = None
        self._det_img_path = None
        _, self.cvt = resize_factory(2448, 2048, target_size=800)

        # 创建右键菜单
        self.menu = QMenu(self)
        self.view_original_action = self.menu.addAction("查看原图")
        self.view_detected_action = self.menu.addAction("查看检测图")

        # 连接信号与槽
        self.view_original_action.triggered.connect(self.view_original)
        self.view_detected_action.triggered.connect(self.view_detected)

    @property
    def img_path(self):
        return self._img_path

    @img_path.setter
    def img_path(self, value):
        self._img_path = value

    @property
    def ori_img_path(self):
        return self._ori_img_path

    @ori_img_path.setter
    def ori_img_path(self, value):
        self._ori_img_path = value

    @property
    def det_img_path(self):
        return self._det_img_path

    @det_img_path.setter
    def det_img_path(self, value):
        self._det_img_path = value

    def __call__(self, img):
        if self.size:
            self.raw_pix = self.pix = img.scaled(*self.size)
            self.setPixmap(self.pix)
        else:
            self.raw_pix = self.pix = img
            self.setPixmap(self.pix)

    def mouseDoubleClickEvent(self, e):
        if e.button() == QtCore.Qt.LeftButton:
            if self.pix.rect().width() > 5000:
                QMessageBox.information(self, '提示', '已放大至最大！', QMessageBox.Yes)
                return
            size = self.pix.size() * 2.0
            self.pix = self.pix.scaled(size)
            size = self.pix.size()
            self.pix = self.pix.copy(e.pos().x(), e.pos().y(), size.width(), size.height())
            self.setPixmap(self.pix)
        else:
            self.pix = self.raw_pix
            self.setPixmap(self.pix)

    def mouseReleaseEvent(self, e):
        if e.button() == QtCore.Qt.RightButton and (self.img_struct is not None):
            clicked_x, clicked_y = e.pos().x(), e.pos().y()
            size = self.pix.size()
            width, height = size.width(), size.height()
            for defect_obj in self.img_struct.filtered_obj_list:
                bbox = defect_obj.bbox
                top, left, bottom, right = bbox
                top = max(self.cvt(top, False), 0)
                left = max(self.cvt(left), 0)
                bottom = min(self.cvt(bottom, False), height)
                right = min(self.cvt(right), width)
                bbox = top, left, bottom, right
                if clicked_obj(clicked_x, clicked_y, bbox):
                    logger.debug(f"clicked defect_obj: {defect_obj.to_dict()}")

    def contextMenuEvent(self, event):
        """重写右键菜单事件"""
        self.menu.exec_(event.globalPos())

    def view_original(self):
        """查看原图"""
        if self._ori_img_path is not None:
            explorer(self._ori_img_path)
        elif self.img_struct.ori_img_path is not None:
            explorer(self.img_struct.ori_img_path)

    def view_detected(self):
        """查看原图"""
        if self._det_img_path is not None:
            explorer(self._det_img_path)
        elif self.img_struct.det_img_path is not None:
            explorer(self.img_struct.det_img_path)


def clicked_obj(clicked_x, clicked_y, bbox):
    return (bbox[0] < clicked_x < bbox[2]) and (bbox[1] < clicked_y < bbox[3])


if __name__ == '__main__':
    import sys
    from common.settings import Settings
    from PySide2.QtGui import QPixmap
    from PySide2.QtWidgets import QApplication

    app = QApplication(sys.argv)
    page = ShowImgPage()
    page.content(QPixmap(Settings.FIRST_LOAD))
    page.show()
    sys.exit(app.exec_())
